package xdb;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

public class Tables {
    private static final SimpleDateFormat sdf;

    static {
        sdf = new SimpleDateFormat("yyyyMMddHHmmss");
        sdf.setLenient(false);
    }

    private final Map<String, Table> tables = new HashMap<>();
    private final ReentrantReadWriteLock flushLock = new ReentrantReadWriteLock();
    // Table 管理 Storage 打开关闭。对于 Table，Storage 是可选的。
    // 这里单独保存一份所有Storage的列表，便于数据表访问。
    private final List<Storage> storages = new ArrayList<>();
    private final TableSys tableSys = new TableSys();

    protected Tables() {
        // add system table
        add(tableSys);
    }

    public final TableSys getTableSys() {
        return tableSys;
    }

    public final Table getTable(String name) {
        return tables.get(name);
    }

    public final Collection<Table> getTables() {
        return tables.values();
    }

    protected final void add(Table table) {
        if (null != tables.put(table.getName(), table)) {
            throw new XError("duplicate table name " + table.getName());
        }
    }

    final void open(XdbConf conf) {
        for (Table table : tables.values()) {
            Storage storage = table.open(conf);
            if (null != storage) {
                storages.add(storage);
            }
        }

        // <<在 table.initialize 前>>先给现有的表分配好锁id。详情请看内部实现。
        xdb.Lockeys.getInstance().initializeLockIdMap(tables.values());
        for (Table table : tables.values()) {
            table.initialize(this);
        }
    }

    final void close() {
        storages.clear();

        for (Table table : tables.values()) {
            table.close();
        }
    }

    final Lock flushReadLock() {
        return flushLock.readLock();
    }

    final boolean isHeldFlushWriteLockByCurrentThread() {
        return flushLock.writeLock().isHeldByCurrentThread();
    }

    final Lock flushWriteLock() {
        return flushLock.writeLock();
    }

    final void logNotify() {
        for (Table table : tables.values()) {
            table.logNotify();
        }
    }

    final List<Storage> getStorages() {
        return storages;
    }
}
